package com.stationpc.androidtvrecents

import android.content.Context
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.Drawable
import android.media.AudioManager
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.TextView
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import kotlinx.coroutines.*

enum class Action {
    OPEN,
    CLOSE
}

class RecentAppsAdapter(
    private val context: Context,
    private val onItemAction: (Int, Action) -> Unit,
    private val onFocusChange: (View, Boolean) -> Unit
) : ListAdapter<AppInfo, RecentAppsAdapter.ViewHolder>(AppDiffCallback()) {

    private val audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
    private val adapterScope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    inner class ViewHolder(view: View) : RecyclerView.ViewHolder(view) {
        private val bannerImage: ImageView = view.findViewById(R.id.app_banner)
        private val appName: TextView = view.findViewById(R.id.app_name)
        private val errorView: TextView = view.findViewById(R.id.error_text)
        private val borderContainer: View = view.findViewById(R.id.border_container)
        private val borderAnimation = borderContainer.background as? AnimationDrawable
        private var iconLoadJob: Job? = null

        init {
            itemView.setOnFocusChangeListener { v, hasFocus ->
                onFocusChange(v, hasFocus)
                borderContainer.visibility = if (hasFocus) View.VISIBLE else View.INVISIBLE
                if (hasFocus) {
                    borderAnimation?.start()
                    playSound(AudioManager.FX_FOCUS_NAVIGATION_RIGHT)
                } else {
                    borderAnimation?.stop()
                }
            }

            itemView.setOnClickListener {
                playSound(AudioManager.FX_KEY_CLICK)
                onItemAction(adapterPosition, Action.OPEN)
            }

            itemView.setOnKeyListener { _, keyCode, event ->
                if (event.action != KeyEvent.ACTION_DOWN) return@setOnKeyListener false

                when (keyCode) {
                    KeyEvent.KEYCODE_DPAD_CENTER, KeyEvent.KEYCODE_ENTER -> {
                        playSound(AudioManager.FX_KEY_CLICK)
                        onItemAction(adapterPosition, Action.OPEN)
                        true
                    }
                    KeyEvent.KEYCODE_DPAD_DOWN -> {
                        playSound(AudioManager.FX_KEYPRESS_DELETE)
                        onItemAction(adapterPosition, Action.CLOSE)
                        true
                    }
                    else -> false
                }
            }
        }

        fun bind(app: AppInfo) {
            appName.text = app.label
            bannerImage.setImageDrawable(null) // Clear previous image
            iconLoadJob?.cancel()
            iconLoadJob = adapterScope.launch(Dispatchers.IO) {
                try {
                    loadAppIcon(app)
                } catch (e: Exception) {
                    withContext(Dispatchers.Main) {
                        showError(context.getString(R.string.error_loading_app))
                    }
                }
            }
        }

        private suspend fun loadAppIcon(app: AppInfo) {
            withContext(Dispatchers.IO) {
                try {
                    val packageManager = context.packageManager
                    val appInfo = packageManager.getApplicationInfo(app.packageName, 0)
                    val icon = packageManager.getApplicationBanner(appInfo)
                        ?: packageManager.getApplicationIcon(appInfo)

                    withContext(Dispatchers.Main) {
                        showContent()
                        bannerImage.setImageDrawable(icon)
                    }
                } catch (e: Exception) {
                    withContext(Dispatchers.Main) {
                        showError(context.getString(R.string.error_loading_app))
                    }
                }
            }
        }

        private fun showError(message: String) {
            errorView.visibility = View.VISIBLE
            errorView.text = message
            bannerImage.visibility = View.GONE
            appName.visibility = View.GONE
        }

        private fun showContent() {
            errorView.visibility = View.GONE
            bannerImage.visibility = View.VISIBLE
            appName.visibility = View.VISIBLE
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        val view = LayoutInflater.from(parent.context)
            .inflate(R.layout.item_recent_app, parent, false)
        return ViewHolder(view)
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.bind(getItem(position))
    }

    private fun playSound(soundEffect: Int) {
        try {
            audioManager.playSoundEffect(soundEffect)
        } catch (e: Exception) {
            // Silently fail if sound cannot be played
        }
    }

    override fun onDetachedFromRecyclerView(recyclerView: RecyclerView) {
        super.onDetachedFromRecyclerView(recyclerView)
        adapterScope.cancel()
    }
}

class AppDiffCallback : DiffUtil.ItemCallback<AppInfo>() {
    override fun areItemsTheSame(oldItem: AppInfo, newItem: AppInfo): Boolean {
        return oldItem.packageName == newItem.packageName
    }

    override fun areContentsTheSame(oldItem: AppInfo, newItem: AppInfo): Boolean {
        return oldItem == newItem
    }
}
